package com.onpositive.mediawiki.deserializing;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;

import com.onpositive.data.IObjectCollection;
import com.onpositive.data.IPropertyMetadata;
import com.onpositive.data.units.DateWithAccuracy;
import com.onpositive.data.units.Unit;
import com.onpositive.data.units.Units;
import com.onpositive.datamap.values.impl.DateRange;
import com.onpositive.datamap.values.impl.ScalarRange;
import com.onpositive.mediawiki.propertyparser.IdentParser;
import com.onpositive.mediawiki.propertyparser.PropertyCharacteristic;
import com.onpositive.mediawiki.serializing.DocumentNamePropertyMetadata;
import com.onpositive.mediawiki.serializing.ParsedPropertyMetadata;
import com.onpositive.mediawiki.serializing.ScalarValueWriter;
import com.onpositive.mediawiki.serializing.ValueSequenceWriter;
import com.onpositive.units.ParsedDate;
import com.onpositive.units.ParsedDimension;
import com.onpositive.units.ParsedFileList;
import com.onpositive.units.ParsedIdent;
import com.onpositive.units.ParsedLinkArray;
import com.onpositive.units.ParsedScalar;
import com.onpositive.units.ParsedSection;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;
import com.onpositive.units.ParsedValueSequenceV2;
import com.onpositive.units.TextContent;
import com.onpositive.units.ValueCluster;

public class PropertyDeserializer {
	
	private PropertyCharacteristic pChar ;
	private IPropertyMetadata mtd ;
	private ArrayList<ParsedValue> values ;
	private IObjectCollection<Integer> collection ;
	private int size ;
	private String name ;
	
	public PropertyCharacteristic getpChar() {
		return pChar;
	}
	public ParsedValue getValue(int i){
		
		if( values == null || values.size() <= i )
			return null ;
		
		return values.get(i) ;
	}
	
	public PropertyDeserializer( IPropertyMetadata mtd, IObjectCollection<Integer> collection )
	{
		this.collection = collection ;
		this.size = collection.size() ;
		values = new ArrayList<ParsedValue>( size ) ;
		this.mtd = mtd ;
		pChar = initChar( mtd ) ;
		
		prepareVlues() ;		
	}
	
	private PropertyCharacteristic initChar(IPropertyMetadata mtd) {
		

		PropertyCharacteristic pc ;
//		if( mtd instanceof ParsedPropertyMetadata )
//			pc = ((ParsedPropertyMetadata)mtd).getChar() ;
//		else
		{		

			pc = new PropertyCharacteristic() ;		
			for( String key : mtd.keys() ){
				try{			
					pc.setCharacteristic( key, mtd.getMetaPropertyValue(key).toString() ) ;
				}catch(Exception e)
				{
					e.printStackTrace() ;
				}
			}
		}
		name = pc.getCharacteristic( PropertyCharacteristic.CHAR_PROPERTY_NAME_LABEL ) ;
		if( name == null )
			name = mtd.id() ;
		
		return pc;
	}
	private void prepareVlues() {
		
		String parserId = pChar.getCharacteristic( PropertyCharacteristic.CHAR_PARSER_ID_LABEL ) ;
		if( parserId == null )
			parserId = mtd.id() ;
		
		for( int i = 0 ; i < size ; i++ ){
			Object value = getValueFromCollection(i) ;
			if( value == null )
				values.add( null );
			else				
				values.add( createParsedValue( value, parserId ) ) ;
		}
		

		
	}
	public Object getValueFromCollection(int i) {
		return collection.getValue( i, mtd);
	}
	
	private static String DEFAULT_DESERIALIZATION_COMMENT = "" ;
	@SuppressWarnings("unchecked")
	private ParsedValue createParsedValue(Object value, String id)
	{
		if( id == null )
			return null;
//		
//		if( id.equals( DocumentNamePropertyMetadata.DOCUMENT_NAME_PROPERTY_METADATA_ID ) )
//			return new ParsedString( (String)value ) ;
		
		if( id.equals( ParsedScalar.ID ) ){
			
			ScalarRange sr = (ScalarRange) value ;
			double lVal = sr.getLowValue() ;
			double uVal = sr.getHighValue() ;
			
			ParsedScalar ps ;
			if( lVal == uVal )
				ps = new ParsedScalar( uVal, DEFAULT_DESERIALIZATION_COMMENT ) ;
			else
				ps = new ParsedScalar(lVal, uVal, DEFAULT_DESERIALIZATION_COMMENT ) ;
			
			String comment = (String) sr.getComment() ;
			if( comment == null )
				return ps ;
			
			comment = "comment:" + comment ;
			
			ValueCluster<ParsedScalar> vc = new ValueCluster<ParsedScalar>(
					new ParsedValue[]{ ps, new ParsedString(comment, DEFAULT_DESERIALIZATION_COMMENT) },
					ParsedScalar.class,
					0,
					DEFAULT_DESERIALIZATION_COMMENT, null ) ;
			
			return vc ;
		}
		
		if( id.equals( ParsedDimension.ID ) ){
			
			String unitName = pChar.getCharacteristic( PropertyCharacteristic.CHAR_UNIT_LABEL );
			String unitKind = pChar.getCharacteristic( PropertyCharacteristic.CHAR_UNIT_KIND_LABEL );
			Unit unit = Units.getUnitByShortName( unitName, unitKind ) ;
			if( unit == null )
				unit = Units.getUnitByShortName("#unit#", null) ;
			
			ScalarRange sr = (ScalarRange) value ;
			double lVal = sr.getLowValue() ;
			double uVal = sr.getHighValue() ;
			
			ParsedDimension pd ;
			if( lVal == uVal )
				pd = new ParsedDimension( uVal, unit, DEFAULT_DESERIALIZATION_COMMENT ) ;
			else
				pd = new ParsedDimension(lVal, uVal, unit, DEFAULT_DESERIALIZATION_COMMENT ) ;
			
			String comment = (String) sr.getComment() ;
			if( comment == null )
				return pd ;
			
			comment = "comment:" + comment ;
			
			ValueCluster<ParsedDimension> vc = new ValueCluster<ParsedDimension>(
					new ParsedValue[]{ pd, new ParsedString(comment, DEFAULT_DESERIALIZATION_COMMENT) },
					ParsedDimension.class,
					0,
					DEFAULT_DESERIALIZATION_COMMENT, null ) ;
			
			return vc ;
		}
		
		if( id.equals( ParsedDate.ID ) ){
			DateRange dr = (DateRange) value ;
			DateWithAccuracy lVal = dr.getLow() ;
			DateWithAccuracy uVal = dr.getHigh() ;
			
			ParsedDate pd ;
			if( lVal.equals(uVal) )
				pd = new ParsedDate( uVal, DEFAULT_DESERIALIZATION_COMMENT ) ;
			else
				pd = new ParsedDate(lVal, uVal, DEFAULT_DESERIALIZATION_COMMENT ) ;
			
			String comment = (String) dr.getComment() ;
			if( comment == null )
				return pd ;
			
			comment = "comment:" + comment ;
			
			ValueCluster<ParsedDate> vc = new ValueCluster<ParsedDate>(
					new ParsedValue[]{ pd, new ParsedString(comment, DEFAULT_DESERIALIZATION_COMMENT) },
					ParsedDate.class,
					0,
					DEFAULT_DESERIALIZATION_COMMENT, null ) ;
			
			return vc ;
		}
		
		if( id.equals( ParsedIdent.ID ) )
			return createParsedValueSequence( (String) value ) ;
			//return new ParsedIdent( (String)value, DEFAULT_DESERIALIZATION_COMMENT ) ;
		
		if( id.equals( ParsedString.ID ) )
			return new ParsedString( (String)value, DEFAULT_DESERIALIZATION_COMMENT ) ;
		
		if( id.equals( ParsedFileList.ID ) )
			return new ParsedFileList( (ArrayList<String>) value, DEFAULT_DESERIALIZATION_COMMENT ) ;
		
		if( id.equals( ParsedLinkArray.ID ) )
			return new ParsedLinkArray( (ArrayList<String>) value, DEFAULT_DESERIALIZATION_COMMENT ) ;

		if( id.equals( ParsedValueSequenceV2.ID ) )
			return createParsedValueSequence( (String) value ) ;
		
		if( id.equals( TextContent.ID ) )
			return createTextContent( value );

		
		return null ;
	}
		
	
	public String getName() {
		return name;
	}
	
	ParsedValueSequence createParsedValueSequence( String value )
	{		
		ParsedValueSequence result = new ParsedValueSequence(DEFAULT_DESERIALIZATION_COMMENT) ;		
		if( value == null || value.length() == 0 )
			return result ;
			
		String[] values = value.split( ValueSequenceWriter.valueSeparator ) ;
		for( String s : values ){
			if( s.trim().length() == 0 )
				continue ;
			
			int prev = 0 ;
			for(  int ind = s.indexOf("[[") ; ind >= 0 ; ind = s.indexOf("[[", prev) ){
				String preceeding = s.substring(prev, ind).trim() ;
				if( preceeding.length() != 0 )
					result.addValue( new ParsedString( preceeding, DEFAULT_DESERIALIZATION_COMMENT ) ) ;
				
				prev = s.indexOf("]]", ind )+2 ;
				result.addValue( new ParsedIdent( s.substring(ind, prev), DEFAULT_DESERIALIZATION_COMMENT )) ;
			}
			String preceeding = s.substring(prev, s.length() ).trim() ;
			if( preceeding.length() != 0 )
				result.addValue( new ParsedString( preceeding, DEFAULT_DESERIALIZATION_COMMENT ) ) ;
			
			//result.addValue( new ParsedString(s, DEFAULT_DESERIALIZATION_COMMENT) ) ;
		}
		return result ;
	}
	
	private ParsedValue createTextContent(Object value)
	{
		byte[] bArr = (byte[]) value ;
		TextContent tc = null ;
		try {
			tc = new TextContent( new String( bArr, "UTF-8"), "" );
		} catch ( UnsupportedEncodingException e ) {
			e.printStackTrace();
			tc = new TextContent( new String( bArr ), "" );
		}
		return tc ;
	}
}
